package fr.dauphine.bookstore.backoffice.book;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanPropertyValueEqualsPredicate;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Session;

import fr.dauphine.bookstore.backoffice.SessionUtil;
import fr.dauphine.bookstore.commun.FormatUtil;
import fr.dauphine.bookstore.commun.MessagesUtil;
import fr.dauphine.bookstore.hibernate.HibernateUtil;
import fr.dauphine.bookstore.modele.Author;
import fr.dauphine.bookstore.modele.Book;

/**
 * Ajout et modification d'un livre.
 */
public final class SaveBookServlet extends HttpServlet {

	/**
	 * Serial version UID.
	 */
	private static final long serialVersionUID = 5347836201142869831L;

	/**
	 * Traite la methode POST.
	 * 
	 * @param request
	 *            Requete
	 * @param response
	 *            Reponse
	 * @throws ServletException
	 *             Erreur de servlet
	 * @throws IOException
	 *             Erreur d'entree/sortie
	 */
	protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
		Book book = SessionUtil.getBook(request.getSession());

		retreiveTitle(request, book);
		retreiveDate(request, book);
		retreivePrice(request, book);
		retreiveCategory(request, book);
		retreiveAuthors(request, book);

		// On sauvegarde
		if (!MessagesUtil.isThereErrors(request)) {

			Session hSession = HibernateUtil.getSessionFactory().getCurrentSession();
			hSession.saveOrUpdate(book);
			SessionUtil.removeBook(request.getSession());

			response.sendRedirect("books.jsp");

			// On retourne sur la page de modification
		} else {
			request.getRequestDispatcher("editBook.jsp").forward(request, response);
		}
	}

	/**
	 * Recupere le titre dans la requete.
	 * 
	 * @param request
	 *            Requete
	 * @param book
	 *            Livre
	 */
	private void retreiveTitle(final HttpServletRequest request, final Book book) {
		book.setTitle(request.getParameter("title"));

		if (StringUtils.isEmpty(book.getTitle())) {
			MessagesUtil.addMessage(request, MessagesUtil.ERROR, "Le titre est obligatoire");
		}
	}

	/**
	 * Recupere la date dans la requete.
	 * 
	 * @param request
	 *            Requete
	 * @param book
	 *            Livre
	 */
	private void retreiveDate(final HttpServletRequest request, final Book book) {
		try {
			Date date = FormatUtil.parseDate(request.getParameter("date"));
			book.setDate(date);

		} catch (ParseException e) {
			MessagesUtil.addMessage(request, MessagesUtil.ERROR, "La date est incorrecte");
		}
	}

	/**
	 * Recupere le prix dans la requete.
	 * 
	 * @param request
	 *            Requete
	 * @param book
	 *            Livre
	 */
	private void retreivePrice(final HttpServletRequest request, final Book book) {
		BigDecimal price = BigDecimal.ZERO;

		try {
			price = new BigDecimal(request.getParameter("price"));

		} catch (NumberFormatException e) {
			MessagesUtil.addMessage(request, MessagesUtil.ERROR, "Le prix est incorrect");
		}

		book.setPrice(price);
	}

	/**
	 * Recupere la categorie dans la requete.
	 * 
	 * @param request
	 *            Requete
	 * @param book
	 *            Livre
	 */
	private void retreiveCategory(final HttpServletRequest request, final Book book) {
		Long id = Long.valueOf(request.getParameter("category"));
		book.getCategory().setId(id);

		if (Long.valueOf(0).equals(id)) {
			MessagesUtil.addMessage(request, MessagesUtil.ERROR, "La categorie est obligatoire");
		}
	}

	/**
	 * Recupere les auteurs dans la requete.
	 * 
	 * @param request
	 *            Requete
	 * @param book
	 *            Livre
	 */
	@SuppressWarnings("unchecked")
	private void retreiveAuthors(final HttpServletRequest request, final Book book) {
		Collection<Author> selectedAuthors = new ArrayList<Author>();

		// On construit une liste contenant les auteurs selectionnes
		for (int i = 0;; i++) {
			String id = request.getParameter("author" + i);

			if (StringUtils.isEmpty(id)) {
				break;
			}

			Author author = new Author();
			author.setId(Long.valueOf(id));
			selectedAuthors.add(author);
		}

		// Auteurs supprimes
		// [A, B] - [B] = [A]
		Collection<Author> toRemove = CollectionUtils.subtract(book.getAuthors(), selectedAuthors);

		// Auteurs ajoutes
		// [A] - [A, B] = [B]
		Collection<Author> toAdd = CollectionUtils.subtract(selectedAuthors, book.getAuthors());

		book.getAuthors().removeAll(toRemove);
		book.getAuthors().addAll(toAdd);

		if (book.getAuthors().isEmpty()) {
			MessagesUtil.addMessage(request, MessagesUtil.ERROR, "Il faut au moins un auteur");

		} else if (CollectionUtils.exists(book.getAuthors(), new BeanPropertyValueEqualsPredicate("id", Long.valueOf(0)))) {

			MessagesUtil.addMessage(request, MessagesUtil.ERROR, "Un auteur (au moins) n'a pas ete selectionne");
		}
	}
}
